package club.baimahu.pencil.miaosha.service;

import club.baimahu.pencil.miaosha.domain.Stock;
import club.baimahu.pencil.miaosha.domain.User;
import club.baimahu.pencil.miaosha.mapper.StockMapper;
import club.baimahu.pencil.miaosha.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static club.baimahu.pencil.miaosha.service.StockService.STOCK_ID_SET;

/**
 * TODO
 *
 * @author zhanghongjiang
 * @version 1.0
 * @date 2021/9/13 22:47
 */

@Slf4j
@Service
public class UserService {

    @Autowired
    UserMapper userMapper;

    @Autowired
    StockMapper stockMapper;

    @Autowired
    public RedisTemplate<String,String> redisTemplate;

    public static final String SALT = "SLAJLJI13*(";

    // 用户hash验证的key前缀
    public static final String VERIFY_KEY_PREFIX = "VERIFY_KEY_PREFIX_";

    // 用户请求订单的次数的key前缀
    public static final String USER_REQUEST_TIME_KEY_PREFIX_ = "USER_REQUEST_TIME_KEY_PREFIX_";

    // 最大请求数，最好能通过后台配置
    public int maxRequestTime = 10 ;



    public static final String USER_ID_SET = "USER_ID_SET";

    @PostConstruct
    public void initUserIdSet(){
        SetOperations<String,String> set =  redisTemplate.opsForSet();
        List<Integer> idList = userMapper.selectUserIds();
        for(Integer id : idList){
            set.add(USER_ID_SET,id.toString());
        }
    }


    public User getUser(Integer id){

        if(id == null){
            throw new IllegalArgumentException("id cannot be null");
        }

        return userMapper.getUser(id);
    }

    public int addUser(User user){
        return userMapper.addUser(user);
    }

    public String getVerifyKey(Integer userId, Integer sid){

        return VERIFY_KEY_PREFIX + userId + "_" + sid;

    }

    public String getRequestTimeKey(Integer userId){

        return USER_REQUEST_TIME_KEY_PREFIX_ + "_" + userId + "_";
    }

    public boolean verify(Integer userId, Integer sid,String verifyHash){

        String key = getVerifyKey(userId,sid);

        String value = redisTemplate.opsForValue().get(key);

        if(value == null){
            log.warn("key=[{}] not exists",key);
            return false;
        }

        return value.equals(verifyHash);
    }

    public void deleteVerifyHash(Integer userId, Integer sid){
        redisTemplate.delete(getVerifyKey(userId,sid));
    }


    public String getVerifyHash(Integer userId, Integer sid) {

        String key = getVerifyKey(userId,sid);

        String value = redisTemplate.opsForValue().get(key);

        if(value != null){
            return value;
        }

        boolean userIdOk = redisTemplate.opsForSet().isMember(USER_ID_SET,String.valueOf(userId));
        boolean stockIdOk = redisTemplate.opsForSet().isMember(STOCK_ID_SET,String.valueOf(sid));
        if(!userIdOk || !stockIdOk){
            return "invalid userId or sid";
        }

//        log.info("queryDB start");
////        long mark1 = System.currentTimeMillis();
////        User user = getUser(userId);
////
////        if(user == null){
////            throw new RuntimeException("user cannot found : id = " + userId);
////        }
////
////        Stock stock = stockMapper.getStock(sid);
////
////        if(stock == null){
////            throw new RuntimeException("stock cannot found : sid = " + sid);
////        }
////
////        long mark2 = System.currentTimeMillis();
////        log.info("queryDB end , use {} ms",mark2 - mark1);

        String verifyHashDraft = userId + "_" + sid + "_" + SALT;

        String verifyHash = DigestUtils.md5DigestAsHex(verifyHashDraft.getBytes());

        long mark3 = System.currentTimeMillis();

        //缓存十分钟，
        redisTemplate.opsForValue().set(key ,verifyHash,600, TimeUnit.SECONDS);

        log.debug("redis set key={},value={}",key,verifyHash);

        return verifyHash;
    }


    public boolean checkUserIsBanned(Integer userId){

        if(userId == null){
            throw new IllegalArgumentException("userId cannot be null");
        }

        String key = getRequestTimeKey(userId);

        String value = redisTemplate.opsForValue().get(key);

        if(value == null){
            return false;
        }

        return Integer.parseInt(value) > maxRequestTime ;

    }

    public void increaseUserRequestTime(Integer userId){

        if(userId == null){
            throw new IllegalArgumentException("userId cannot be null");
        }

        String key = getRequestTimeKey(userId);

        //计数加1
        long val = redisTemplate.opsForValue().increment(key,1L);

        // key 初始化时 ， 并设置5分钟后过期（等于设置惩罚时间），这样可以保证用户5分钟后可继续正常请求
        if(val == 1L){
            redisTemplate.expire(key , 5 ,TimeUnit.MINUTES );
        }

    }
}
